package com.hoas.keystore.util;

import org.apache.commons.codec.binary.Hex;
import org.apache.commons.codec.digest.DigestUtils;

import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.security.Key;
import java.security.SecureRandom;

import static com.hoas.keystore.util.Base64Util.decryptBASE64;
import static com.hoas.keystore.util.Base64Util.encryptBASE64;

public class AESUtil {

    /**
     * ALGORITHM 算法
     * 可替换为以下任意一种算法，同时key值的size相应改变。
     * DES          		key size must be equal to 56
     * DESede(TripleDES) 	key size must be equal to 112 or 168
     * AES          		key size must be equal to 128, 192 or 256,but 192 and 256 bits may not be available
     * Blowfish     		key size must be multiple of 8, and can only range from 32 to 448 (inclusive)
     * RC2          		key size must be between 40 and 1024 bits
     * RC4(ARCFOUR) 		key size must be between 40 and 1024 bits
     * 在Key toKey(byte[] key)方法中使用下述代码
     * SecretKey secretKey = new SecretKeySpec(key, ALGORITHM);替换
     * DESKeySpec dks = new DESKeySpec(key);
     * SecretKeyFactory keyFactory = SecretKeyFactory.getInstance(ALGORITHM);
     * SecretKey secretKey = keyFactory.generateSecret(dks);
     */
    public static final String ALGORITHM = "AES";
    public static final String ALGORITHM_CBC = "AES/CBC/PKCS5Padding";
    public static final int KEY_INIT_SIZE = 128;

    /**
     * 转换密钥<br>
     *
     * @param key
     * @return
     * @throws Exception
     */
    private static Key toKey(byte[] key) throws Exception {
	/*
	 * 	DESKeySpec dks = new DESKeySpec(key);
		SecretKeyFactory keyFactory = SecretKeyFactory.getInstance(ALGORITHM);
		SecretKey secretKey = keyFactory.generateSecret(dks);
      */
        // 当使用其他对称加密算法时，如AES、Blowfish等算法时，用下述代码替换上述三行代码
        SecretKey secretKey = new SecretKeySpec(key, ALGORITHM);

        return secretKey;
    }

    /**
     * 解密
     *
     * @param data
     * @param key
     * @param ivstr CBC模式使用，非CBC模式传null
     *
     * @return
     * @throws Exception
     */
    public static byte[] decrypt(byte[] data, String key, String ivstr) throws Exception {
        Key k = toKey(decryptBASE64(key));

        Cipher cipher = Cipher.getInstance(ALGORITHM);

        if (ivstr != null && ivstr.length() > 0) {
            IvParameterSpec iv = new IvParameterSpec(ivstr.getBytes());//使用CBC模式，需要一个向量iv，可增加加密算法的强度
            cipher.init(Cipher.ENCRYPT_MODE, k, iv);
        } else {
            cipher.init(Cipher.DECRYPT_MODE, k);
        }


        return cipher.doFinal(data);
    }

    /**
     * 加密
     *
     * @param data
     * @param key
     * @param ivstr CBC模式使用，非CBC模式传null
     *
     * @return
     * @throws Exception
     */
    public static byte[] encrypt(byte[] data, String key, String ivstr) throws Exception {
        Key k = toKey(decryptBASE64(key));


        if (ivstr != null && ivstr.length() > 0) {

            Cipher cipher = Cipher.getInstance(ALGORITHM_CBC);
            IvParameterSpec iv = new IvParameterSpec(ivstr.getBytes());
            cipher.init(Cipher.DECRYPT_MODE, k, iv);
            return cipher.doFinal(data);

        } else {

            Cipher cipher = Cipher.getInstance(ALGORITHM);
            cipher.init(Cipher.ENCRYPT_MODE, k);
            return cipher.doFinal(data);

        }

    }

    /**
     * 摘要处理
     *
     * @param data 待摘要数据
     * @return 摘要字符串
     */
    public static String sign(byte[] data) {
        return DigestUtils.md5Hex(data);
    }
    /**
     * 验证
     *
     * @param data 待摘要数据
     * @param messageDigest 摘要字符串
     * @return 验证结果
     */
    public static boolean verify(byte[] data, String messageDigest) {
        return messageDigest.equals(sign(data));
    }

    /**
     * 生成密钥
     *
     * @return
     * @throws Exception
     */
    public static String gen() throws Exception {

       return gen(null);
    }

    public static String encryptHex(byte[] key) {
        return Hex.encodeHexString(key);
    }

    /**
     * 生成密钥
     *
     * @param seed
     * @return
     * @throws Exception
     */
    public static String gen(String seed) throws Exception {
        SecureRandom secureRandom = null;

        if (seed != null) {
            secureRandom = new SecureRandom(decryptBASE64(seed));
        } else {
            secureRandom = new SecureRandom();
        }

        KeyGenerator kg = KeyGenerator.getInstance(ALGORITHM);
        kg.init(secureRandom);

        SecretKey secretKey = kg.generateKey();

        return encryptBASE64(secretKey.getEncoded());
    }

    private static byte[] getIV(String str){
        byte[] iv = new byte[]{ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 };

        int len = iv.length - str.length(); // 10
        byte[] strB = str.getBytes();
        for (int i= 0; i < str.length(); i++) {
            iv[i + len] = strB[i];
        }
        System.out.println(new String(iv));
        return iv;
    }


    public static void main(String[] args) {
        try {

//            System.out.println(gen(null));

            String s = "BlQaOx0Ppzo7+aEPOyBAyA==";

            String content = encryptBASE64(encrypt( "{\"userId\":\"2055667\",\"channelVersion\":\"2.0.21\",\"clientType\":\"android\"}".getBytes(), s, null));

            System.out.println(content);

//            content = "z5MlxOpXP3ToFa3Q95maWlgCNw1oqeo+2S+rybbHeIRTeWMGIbDuK8fgz6EOcUAQvEKSymEVRE8X8KioeZ1zFRBG5ikBrKNGL28rnvXsSOg=";
//            byte[] c = decrypt(decryptBASE64(content), s, null);
//            System.out.println(new String(c));

        } catch (Exception e) {
            e.printStackTrace();
        }
    }


}
